"""Simulated connector for test and development scenarios."""

from __future__ import annotations

from datetime import datetime
from typing import Any

from app.connectors.base import BaseConnector, ConnectionStatus, DataPoint, DataQuality
from app.connectors.exceptions import ReadError, WriteError


class SimulatedConnector(BaseConnector):
    """Connector that serves deterministic data without external dependencies."""

    def __init__(self, config: dict[str, Any]) -> None:
        super().__init__(config)
        self._default_quality = config.get("default_quality", "good")
        self._metadata: dict[str, Any] = config.get("metadata", {})
        self._points: dict[str, dict[str, Any]] = {}

        points = config.get("mock_points", {})
        for address, entry in points.items():
            self._points[address] = self._normalize_entry(address, entry)

    def _normalize_entry(self, address: str, entry: Any) -> dict[str, Any]:
        if isinstance(entry, dict):
            value = entry.get("value", 0.0)
            quality = entry.get("quality", self._default_quality)
            unit = entry.get("unit")
            metadata = entry.get("metadata") or {}
        else:
            value = entry
            quality = self._default_quality
            unit = None
            metadata = {}

        try:
            numeric_value = float(value)
        except (TypeError, ValueError) as exc:
            raise ValueError(
                f"Simulated connector requires numeric value for '{address}', got {value!r}"
            ) from exc

        try:
            quality_enum = DataQuality(quality)
        except ValueError:
            quality_enum = DataQuality.GOOD

        return {
            "value": numeric_value,
            "quality": quality_enum,
            "unit": unit,
            "metadata": metadata,
        }

    async def connect(self) -> bool:
        """Mark the connector as connected."""
        self.status = ConnectionStatus.CONNECTED
        return True



    async def disconnect(self) -> bool:
        """Mark the connector as disconnected."""
        self.status = ConnectionStatus.DISCONNECTED
        return True

    async def read_single(self, address: str) -> DataPoint:
        if address not in self._points:
            raise ReadError(f"Simulated point '{address}' not found")
        entry = self._points[address]
        metadata = {**self._metadata, **entry.get("metadata", {})}
        return DataPoint(
            value=entry["value"],
            timestamp=datetime.utcnow(),
            quality=entry["quality"],
            unit=entry["unit"],
            address=address,
            metadata=metadata,
        )

    async def read_multiple(self, addresses: list[str]) -> list[DataPoint]:
        return [await self.read_single(address) for address in addresses]

    async def write_single(self, address: str, value: Any) -> bool:
        try:
            numeric_value = float(value)
        except (TypeError, ValueError) as exc:
            raise WriteError(
                f"Simulated connector requires numeric value, got {value!r}"
            ) from exc

        entry = self._points.get(address)
        if entry is None:
            entry = self._normalize_entry(address, numeric_value)
            self._points[address] = entry
        else:
            entry["value"] = numeric_value
        return True
